package com.skyyan.netty.jjf.protocol;

/**
 * C.5 充值管理机注册确认报文
 * AFN = 0x92
 *
 * 上行报文格式（设备 → 中心）：
 * 起始字符0x68
 * 长度1个字节
 * 起始字符0x68
 * - 控制域C：0x01
 * - 地址域： 9字节  ;[0]-[5]为 区域号;[6]-[8]手持终端设备序列号
 *   地址域[0]-[5] BCD码  五级行政编码示例为:河南省郑州市中牟县官渡镇邵岗村委会 如410122102201
 *   地址域[6]-[8]     手持终端设备序列号 16 进制 低位在前，高位在后
 * - AFN(1字节)：0x92
 * - 数据域16个字节
 *   数据域[0]-[15] 设备注册号 16进制,低位在前 高位在后
 * - CRC8(1字节)
 * -结束字符 0x16
 *
 * 下行报文格式（中心 →设备）：
 * 起始字符0x68
 * 长度1个字节
 * 起始字符0x68
 * - 控制域C：0x00
 * - AFN(1字节)：0x92
 * - 数据域1个字节 BCD码；00成功，01失败（注册号不是服务器返回信息）
 * - CRC8(1字节)
 * -结束字符 0x16
 * @author skyyan
 */
public class RegisterConfirmMessage extends Message {

    /**
     * 上行注册确认报文（设备 → 中心）
     * 需要参数：行政区域编码、手持终端设备序列号、设备注册号
     */
    public static class Uplink extends RegisterConfirmMessage {
        // 行政区域编码 (BCD码，6字节)
        private byte[] areaCodeBytes;
        // 手持终端设备序列号 (HEX，3字节，低位在前)
        private byte[] deviceSerialNoBytes;
        // 设备注册号 (16字节，低位在前)
        private byte[] deviceRegIdBytes;

        /**
         * 构造一个上行的注册确认报文
         * @param address 地址域 (9字节)
         * @param userData 用户数据（设备注册号）
         */
        public Uplink(byte[] address, byte[] userData) {
            super(FrameConstants.CONTROL_UPLINK, address, userData);

            // 从地址域中提取行政区域编码和手持终端设备序列号
            if (address != null && address.length == 9) {
                this.areaCodeBytes = new byte[6];
                this.deviceSerialNoBytes = new byte[3];
                System.arraycopy(address, 0, this.areaCodeBytes, 0, 6);
                System.arraycopy(address, 6, this.deviceSerialNoBytes, 0, 3);
            }
            this.deviceRegIdBytes = userData != null ? userData.clone() : new byte[0];
        }
        
        /**
         * 获取行政区域编码字节数组
         * @return 行政区域编码 (BCD码，6字节)
         */
        public byte[] getAreaCodeBytes() {
            return areaCodeBytes != null ? areaCodeBytes.clone() : new byte[0];
        }

        /**
         * 获取手持终端设备序列号
         * @return 手持终端设备序列号 (HEX，3字节，低位在前)
         */
        public byte[] getDeviceSerialNo() {
            return deviceSerialNoBytes != null ? deviceSerialNoBytes.clone() : new byte[0];
        }

        /**
         * 获取设备注册号
         * @return 设备注册号 (16字节，低位在前)
         */
        public byte[] getDeviceRegId() {
            return deviceRegIdBytes != null ? deviceRegIdBytes.clone() : new byte[0];
        }

        @Override
        public String toString() {
            return "RegisterConfirmMessage.Uplink{" +
                    "control=0x" + String.format("%02X", getControl()) +
                    ", afn=0x" + String.format("%02X", getAfn()) +
                    ", areaCode=" + bytesToHex(getAreaCodeBytes()) +
                    ", deviceSerialNo=" + bytesToHex(getDeviceSerialNo()) +
                    ", deviceRegId=" + bytesToHex(getDeviceRegId()) +
                    '}';
        }
    }

    /**
     * 下行注册确认报文（中心 → 设备）
     * 需要参数：注册结果
     */
    public static class Downlink extends RegisterConfirmMessage {
        // 注册结果 (1字节，0x00表示成功，0x01表示失败)
        private byte registerResult;

        /**
         * 构造一个下行的注册确认报文
         * @param registerResult 注册结果 (0x00表示成功，0x01表示失败)
         */
        public Downlink(byte registerResult) {
            super(FrameConstants.CONTROL_DOWNLINK, null, new byte[]{registerResult});
            this.registerResult = registerResult;
        }

        /**
         * 供解码器使用的构造函数
         * @param address 地址域
         * @param userData 用户数据（注册结果）
         */
        public Downlink(byte[] address, byte[] userData) {
            super(FrameConstants.CONTROL_DOWNLINK, address, userData);
            this.registerResult = (userData != null && userData.length > 0) ? userData[0] : FrameConstants.RESULT_REG_FAIL;
        }

        /**
         * 获取注册结果
         * @return 注册结果 (0x00表示成功，0x01表示失败)
         */
        public byte getRegisterResult() {
            return registerResult;
        }

        /**
         * 设置注册结果
         * @param registerResult 注册结果 (0x00表示成功，0x01表示失败)
         */
        public void setRegisterResult(byte registerResult) {
            this.registerResult = registerResult;
            setUserData(new byte[]{registerResult});
        }
        
        @Override
        public String toString() {
            byte[] address = getAddress();
            return "RegisterConfirmMessage.Downlink{" +
                    "control=0x" + String.format("%02X", getControl()) +
                    ", afn=0x" + String.format("%02X", getAfn()) +
                    ", address=" + (address != null ? bytesToHex(address) : "null") +
                    ", registerResult=0x" + String.format("%02X", getRegisterResult()) +
                    '}';
        }
    }

    /**
     * 供内部使用的构造函数
     * @param control 控制域
     * @param address 地址域
     * @param afn AFN功能码
     * @param userData 用户数据
     */
    protected RegisterConfirmMessage(byte control, byte[] address, byte afn, byte[] userData) {
        super(control, address, afn, userData);
    }

    /**
     * 供解码器使用的构造函数
     * @param control 控制域
     * @param address 地址域
     * @param userData 用户数据
     */
    public RegisterConfirmMessage(byte control, byte[] address, byte[] userData) {
        super(control, address, FrameConstants.AFN_REGISTER_CONFIRM, userData);
    }

    /**
     * 将字节数组转换为十六进制字符串表示
     * @param bytes 字节数组
     * @return 十六进制字符串
     */
    private static String bytesToHex(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return "[]";
        }

        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < bytes.length; i++) {
            if (i > 0) {
                sb.append(" ");
            }
            sb.append(String.format("%02X", bytes[i] & 0xFF));
        }
        sb.append("]");
        return sb.toString();
    }

    /**
     * 创建一个示例地址域
     * @param provinceCode 省代码 (2字节BCD)
     * @param cityCode 市代码 (1字节BCD)
     * @param townCode 镇代码 (3字节BCD)
     * @param stationId 测站编码 (3字节二进制，小端)/或是手持终端序列号
     * @return 9字节地址域
     */
    public static byte[] createAddress(short provinceCode, byte cityCode,
                                       byte[] townCode, int stationId) {
        if (townCode == null || townCode.length != 3) {
            throw new IllegalArgumentException("镇代码必须为3字节");
        }

        byte[] address = new byte[9];
        // A1: 省市代码 (3字节BCD)
        address[0] = (byte) ((provinceCode >> 8) & 0xFF);
        address[1] = (byte) (provinceCode & 0xFF);
        address[2] = cityCode;

        // A2: 镇村代码 (3字节BCD)
        System.arraycopy(townCode, 0, address, 3, 3);

        // A3/这里是设备编码: 测站编码 (3字节二进制，小端)
        address[6] = (byte) (stationId & 0xFF);
        address[7] = (byte) ((stationId >> 8) & 0xFF);
        address[8] = (byte) ((stationId >> 16) & 0xFF);

        return address;
    }

    /**
     * 创建地址域（AD）：6字节BCD区划码 + 3字节小端设备ID
     *
     * @param quhua     区划码，纯数字字符串，用于BCD编码，长度最多12位（对应6字节）
     * @param deviceId  设备ID，十六进制字符串（如 "1A2B3C"），表示24位设备号，取低3字节
     * @return byte[9]：前6字节为quhua的BCD编码，后3字节为deviceId的小端二进制值
     * @throws IllegalArgumentException 如果输入不合法
     */
    public static byte[] createAD(String quhua, String deviceId) throws IllegalArgumentException {
        byte[] result = new byte[9]; // 固定9字节

        // ================== 1. 校验并处理区划码 (quhua) ==================
        if (quhua == null || quhua.isEmpty()) {
            throw new IllegalArgumentException("区划码（quhua）不能为空");
        }

        // 只保留数字字符
        String cleanedQuhua = quhua.replaceAll("[^0-9]", "");
        if (cleanedQuhua.isEmpty()) {
            throw new IllegalArgumentException("区划码必须包含数字");
        }

        if (cleanedQuhua.length() > 12) {
            throw new IllegalArgumentException("区划码数字位数不能超过12位（对应6字节BCD）");
        }

        // 不足12位前面补0
        cleanedQuhua = String.format("%12s", cleanedQuhua).replace(' ', '0');

        // BCD编码：每两位数字合成一个字节
        for (int i = 0; i < 6; i++) {
            int high = Character.digit(cleanedQuhua.charAt(i * 2), 10);
            int low  = Character.digit(cleanedQuhua.charAt(i * 2 + 1), 10);
            result[i] = (byte) ((high << 4) | low);
        }

        // ================== 2. 校验并处理设备ID (deviceId) ==================
        if (deviceId == null || deviceId.isEmpty()) {
            throw new IllegalArgumentException("设备ID（deviceId）不能为空");
        }

        // 清除非十六进制字符
        String cleanedDeviceId = deviceId.replaceAll("[^0-9A-Fa-f]", "");
        if (cleanedDeviceId.isEmpty()) {
            throw new IllegalArgumentException("设备ID必须包含有效的十六进制字符");
        }

        if (cleanedDeviceId.length() > 6) {
            // 超过6位取低24位（即后6位）
            cleanedDeviceId = cleanedDeviceId.substring(cleanedDeviceId.length() - 6);
        }

        // 补足6位（前面补0）
        cleanedDeviceId = String.format("%6s", cleanedDeviceId).replace(' ', '0');

        try {
            // 将16进制字符串转为整数（24位）
            int devIdValue = Integer.parseInt(cleanedDeviceId, 16); // 安全，最多6位

            // 写入3字节，小端序：低字节在前
            result[6] = (byte) (devIdValue       & 0xFF);
            result[7] = (byte) ((devIdValue >> 8)  & 0xFF);
            result[8] = (byte) ((devIdValue >> 16) & 0xFF);

        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("设备ID包含无效的十六进制字符: " + deviceId, e);
        }
        return result;
    }
}